package com.zhouheng.springbootactiviti.common.security;

import com.zhouheng.springbootactiviti.common.constants.ActivitiConstants;
import com.zhouheng.springbootactiviti.common.constants.SecurityConstants;
import com.zhouheng.springbootactiviti.module.mapper.SysMenuMapper;
import io.jsonwebtoken.Jwts;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;


public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    private final SysMenuMapper sysMenuMapper;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager, SysMenuMapper sysMenuMapper) {
        super(authenticationManager);
        this.sysMenuMapper = sysMenuMapper;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String header = request.getHeader(SecurityConstants.HEADER_AUTH);
        if (header == null || !header.startsWith(SecurityConstants.AUTH_HEADER_START_WITH)) {
            chain.doFilter(request, response);
            return;
        }
        UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // activiti需要设置，可能是根据代理人获取任务时需要
        org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(authentication.getPrincipal().toString());
        chain.doFilter(request, response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(SecurityConstants.HEADER_AUTH);
        // token格式错误及乱传的那种抛出的异常，我们不需要处理
        String userName = Jwts.parser()
                .setSigningKey(SecurityConstants.SIGNING_KEY)
                .parseClaimsJws(token.replace(SecurityConstants.AUTH_HEADER_START_WITH, ""))
                .getBody()
                .getSubject();
        List<GrantedAuthorityImpl> authorityList = getAuthorityList(userName);
        return new UsernamePasswordAuthenticationToken(userName, null, authorityList);
    }

    private List<GrantedAuthorityImpl> getAuthorityList(String userName) {
        List<String> menuCodes = sysMenuMapper.getMenuCodeByUserName(userName);
        List<GrantedAuthorityImpl> grantedAuthorityImpls = menuCodes.stream()
                .map(menuCode -> new GrantedAuthorityImpl(SecurityConstants.ROLE_PREFIX + menuCode))
                .collect(Collectors.toList());
        // activitiApi需要ROLE_ACTIVITI_USER权限
        grantedAuthorityImpls.add(new GrantedAuthorityImpl(ActivitiConstants.ROLE_ACTIVITI_USER));
        return grantedAuthorityImpls;
    }

}
